package dao

import (
	"context"
	"fmt"
	"math/rand"
	"proxy_resource_test/utils/logging"
	"sync"
	"time"
)

// DBFactory 定义通用数据库工厂接口
type DBFactory interface {
	Connect(ctx context.Context) error
	Close() error
}

// 全局工厂注册与实例
var (
	onceInit  sync.Once
	onceClose sync.Once
)

func init() {
	RegisterFactory(&MySQLFactory{}) // mysql
}

func SetUp(ctx context.Context) error {
	var initErr error

	onceInit.Do(func() {
		var wg sync.WaitGroup
		var mu sync.Mutex
		errs := make([]error, 0)

		for _, f := range factories {
			wg.Add(1)
			go func(f DBFactory) {
				defer wg.Done()
				if err := retry(ctx, 3, 2*time.Second, func() error { return f.Connect(ctx) }); err != nil {
					mu.Lock()
					errs = append(errs, err)
					mu.Unlock()
				}
			}(f)
		}

		wg.Wait()
		if len(errs) > 0 {
			initErr = fmt.Errorf("数据库初始化失败: %v", errs)
		}
	})
	logging.Warn("数据库连接成功:len", len(factories))
	return initErr
}

// retry 扩展的重试函数，支持上下文、指数退避与抖动
func retry(ctx context.Context, attempts int, baseDelay time.Duration, fn func() error) error {
	for i := 0; i < attempts; i++ {
		err := fn()
		if err == nil {
			return nil
		}
		if i == attempts-1 {
			return err
		}
		d := baseDelay * (1 << i)
		d += time.Duration(rand.Int63n(int64(baseDelay)))
		select {
		case <-time.After(d):
		case <-ctx.Done():
			return ctx.Err()
		}
	}
	return fmt.Errorf("retry attempts exhausted")
}

// Close 关闭所有数据库连接
func Close() error {
	var closeErr error
	onceClose.Do(func() {
		errs := make([]error, 0)
		for _, f := range factories {
			if err := f.Close(); err != nil {
				errs = append(errs, err)
			}
		}
		if len(errs) > 0 {
			closeErr = fmt.Errorf("数据库关闭失败: %v", errs)
			logging.Error("数据库关闭异常: %v", closeErr)
		} else {
			logging.Info("所有数据库连接已正常关闭")
		}
	})
	return closeErr
}
